/*
 * 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙，邂逅框架梦]
 * 
 * https://zhiqim.org/project/zhiqim_framework/zhiqim_kernel.htm
 *
 * Zhiqim Kernel is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *          http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */
package org.zhiqim.kernel.model.codes;

import org.zhiqim.kernel.constants.CodeConstants;

/**
 * Base64编码<br>
 * 
 * 把3个8位字节（3*8=24）转化为4个6位的字节（4*6=24），之后在每个6位的前面补两个0，形成8位，即一个字节。<br>
 * 再根据每个字节的值，用下表中的值替换，不足4个字节的，后补'='。<br><br>
 * 
 * 从BASE64表[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/]中取值。
 * 
 * 例如，凡狐(GBK)（0xB7B2BAFC），先将三个字节（0xB7B2BA）分割成四个字节（0x2D3B0A3A），用BASE64表值替换为（t7K6）；<br>
 * 再将（0xBD）分割成（0x3F00）用BASE64表值替换为（/A），再补两个（=），合起来就形成了编码后的字符串（t7K6/A==）。<br>
 *
 * @version v1.0.0 @author zouzhigang 2014-3-21 新建与整理
 */
public class Base64Encoder implements CodeConstants
{
    /** Base64编码 */
    public static byte[] encode(byte[] src)
    {
        //第一步，计算编码后的长度
        int length = src.length / 3;
        int remainderLen = src.length % 3;
                
        //3字节换成4字节后的长度，余数补成1个字节
        int destLen = (remainderLen == 0)?length * 4:(length + 1) * 4;
        byte[] dest = new byte[destLen];

        //第二步，对标准长度进行处理
        for (int i=0;i<length;i++)
        {
            int srcIndex = i * 3;
            int destIndex = i * 4;
            
            byte s1 = src[srcIndex];
            byte s2 = src[srcIndex+1];
            byte s3 = src[srcIndex+2];
            
            //将3字节按网络顺序转成4字节(byte位运算时先通过&0xFF转成无符号整型)，格式为[00000000 S1S1S1S1 S2S2S2S2 S3S3S3S3]
            int d = 0 << 24 | (s1 & 0xFF) << 16 | (s2 & 0xFF) << 8 | (s3 & 0xFF);
            
            //分别取8-13,14-19,20-25,26-31，与0x3F作运算前补0
            dest[destIndex]   = _BASE64_BS_[d >>> 18 & 0x3F];//取00000000 00000000 00000000 00S1S1S1 & 00000000 00000000 00000000 00111111 = 00S1S1S1
            dest[destIndex+1] = _BASE64_BS_[d >>> 12 & 0x3F];//取00000000 00000000 0000S1S1 S1S1S2S2 & 00000000 00000000 00000000 00111111 = 00S1S2S2
            dest[destIndex+2] = _BASE64_BS_[d >>> 6  & 0x3F];//取00000000 000000S1 S1S1S1S2 S2S2S2S3 & 00000000 00000000 00000000 00111111 = 00S2S2S3
            dest[destIndex+3] = _BASE64_BS_[d        & 0x3F];//取00000000 S1S1S1S1 S2S2S2S2 S3S3S3S3 & 00000000 00000000 00000000 00111111 = 00S3S3S3
        }

        if (remainderLen == 0)
            return dest;
        
        //第三步，对剩余的长度进行处理(remainderLen=[1,2])
        int srcIndex = length * 3;
        int destIndex = length * 4;
        if (remainderLen == 1)
        {//剩1个字节
            byte s1 = src[srcIndex];
            
            //将1个字节转成格式为[00000000 00000000 0000S1S1 S1S10000]，右补4个0保证每6位一组
            int d = (s1 & 0xFF) << 4;
            
            dest[destIndex]     = _BASE64_BS_[d >>> 6 & 0x3F];//取00000000 00000000 00000000 00S1S1S1 & 00000000 00000000 00000000 00111111 = 00S1S1S1
            dest[destIndex + 1] = _BASE64_BS_[d       & 0x3F];//取00000000 00000000 00S1S1S1 S1S10000 & 00000000 00000000 00000000 00111111 = 00S10000
            dest[destIndex + 2] = _BASE64_PAD_;
            dest[destIndex + 3] = _BASE64_PAD_;
        }
        else
        {//剩2个字节
            byte s1 = src[srcIndex];
            byte s2 = src[srcIndex+1];
            
            //将2个字节转成格式为[00000000 000000S1 S1S1S1S2 S2S2S200]，右补2个0保证每6位一组，原2*8=16变为18=3*6
            int d = (s1 & 0xFF) << 10 | (s2 &0xFF) << 2;
            
            //第一字节取原1字节00123456，第二字节取原1字节0078+2字节1234，第三字节取2字节00567800
            dest[destIndex]     = _BASE64_BS_[d >>> 12 & 0x3F];//取00000000 00000000 000000S1 00S1S1S1 & 00000000 00000000 00000000 00111111 = 00S1S1S1
            dest[destIndex + 1] = _BASE64_BS_[d >>> 6  & 0x3F];//取00000000 00000000 0000S1S1 S1S1S2S2 & 00000000 00000000 00000000 00111111 = 00S1S2S2
            dest[destIndex + 2] = _BASE64_BS_[d        & 0x3F];//取00000000 000000S1 S1S1S1S2 S2S2S200 & 00000000 00000000 00000000 00111111 = 00S2S200
            dest[destIndex + 3] = _BASE64_PAD_;
        }

        return dest;
    }
}
